/**
 * 
 */
package pl.com.like.sequoia.biojava.pdb.impl;

import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.biojava.bio.structure.Chain;
import org.biojava.bio.structure.PDBHeader;
import org.biojava.bio.structure.Structure;
import org.biojava.bio.structure.StructureImpl;
import org.biojava.bio.structure.io.PDBFileReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import pl.com.like.sequoia.biojava.pdb.IPdbService;
import pl.com.like.sequoia.biojava.pdb.transform.IPdbCompare;
import pl.com.like.sequoia.biojava.util.impl.ConnectService;
import pl.com.like.sequoia.exceptions.LogicalException;
import pl.com.like.sequoia.model.bio.BioObjectAlign;
import pl.com.like.sequoia.model.bio.BioObjectHandler;
import pl.com.like.sequoia.model.bio.BioParam;
import pl.com.like.sequoia.model.bio.enums.FileTypeEnum;
import pl.com.like.sequoia.model.bio.enums.PdbDefEnum;

/**
 * Service used for connecting with RCSB.org
 * 
 * @author Pawel Wolanski
 * 
 */
public class PdbService extends ConnectService implements IPdbService {

	private final static Logger log = LoggerFactory.getLogger(PdbService.class);

	private IPdbCompare pdbCompare;

	private final FileTypeEnum type = FileTypeEnum.PDB_ZIP;

	public BioObjectHandler compareStrucs(String strucId, String strucId2) {
		Assert.hasLength(strucId);
		Assert.hasLength(strucId2);
		BioObjectHandler retVal = null;
		BioObjectHandler objA = getObject(strucId);
		BioObjectHandler objB = getObject(strucId2);
		if ((objA != null) && (objB != null)) {
			retVal = pdbCompare.compare(objA, objB);
		}
		return retVal;
	}

	@Override
	public void completeOptionals(BioObjectHandler bio) throws LogicalException {
		Assert.notNull(bio);
		PDBFileReader pdbReader = new PDBFileReader();
		try {
			Structure structure = pdbReader.getStructure(bio.getPath());
			PDBHeader pdbHeader = structure.getPDBHeader();
			for (PdbDefEnum enumItem : PdbDefEnum.values()) {
				BioParam bioItem = new BioParam();
				String value = null;
				switch (enumItem) {
					case CLASSIFICATION:
						value = pdbHeader.getClassification();
						break;
					case TECHNIQUE:
						value = pdbHeader.getTechnique();
						break;
					case TITLE:
						value = pdbHeader.getTitle();
						break;
				}
				if (value == null) {
					continue;
				}
				bioItem.setParentId(bio.getId());
				bioItem.setValue(value);
				bioItem.setKey(enumItem);
				getBioParamDao().save(bioItem);
			}
			bio.setChecked(Boolean.TRUE);
			getBioObjectHandlerDao().saveOrUpdate(bio);
		} catch (IOException e) {
			String msg = MessageFormat.format("could not parse downloaded file {0} for object {1}", bio.getPath(), bio
					.getName());
			log.warn(msg, e);
			throw new LogicalException(msg, e);
		}

	}

	public void deleteObject(BioObjectHandler bio) throws LogicalException {
		Assert.notNull(bio);
		String path = bio.getPath();
		File delF = new File(path);
		delF.delete();
		getBioObjectHandlerDao().remove(bio);
	}

	public List<BioObjectHandler> getComparisonPairs(String idComparison) {
		Assert.notNull(idComparison);
		return getConnectionHelper().getComparisonPair(idComparison);
	}

	public List<String> getExtraRasmolScript(String strucId) {
		List<String> inRasmolData = new ArrayList<String>();
		if (StringUtils.hasLength(strucId)) {
			BioObjectAlign align = getConnectionHelper().getSearchAlign(strucId);
			String aLine = align.getBioAAlign();
			inRasmolData.add(aLine);
			inRasmolData.add(align.getBioBAlign());
		}
		return inRasmolData;
	}

	public BioObjectHandler getObject(String idObject) throws LogicalException {
		BioObjectHandler bioHandler = getConnectionHelper().getObject(idObject, getType());
		if (Boolean.FALSE.equals(bioHandler.getChecked())) {
			completeOptionals(bioHandler);
		}
		return bioHandler;
	}

	public BioObjectAlign getObjectAlign(String strucId) {
		return getConnectionHelper().getSearchAlign(strucId);
	}

	public IPdbCompare getPdbCompare() {
		return pdbCompare;
	}

	public String getPdbObjectString(String strucId, String strucId2) {
		Assert.hasLength(strucId);
		Assert.hasLength(strucId2);
		String retVal = null;
		BioObjectHandler objA = getObject(strucId);
		BioObjectHandler objB = getObject(strucId2);
		if ((objA != null) && (objB != null)) {
			try {
				Structure nStruc = new StructureImpl();
				PDBFileReader pr = new PDBFileReader();
				Structure struc;
				struc = pr.getStructure(objA.getPath());
				List<Chain> chains = struc.getChains();
				nStruc.addModel(chains);
				struc = pr.getStructure(objB.getPath());
				chains = struc.getChains();
				nStruc.addModel(chains);
				nStruc.setNmr(true);
				retVal = nStruc.toPDB();
			} catch (IOException e) {
				log.error(MessageFormat.format("exception raised while converting elements {0} & {1} to string",
						strucId, strucId2), e);
			}
		}
		return retVal;
	}

	@Override
	protected FileTypeEnum getType() {
		return type;
	}

	public void setPdbCompare(IPdbCompare pdbCompare) {
		this.pdbCompare = pdbCompare;
	}

	public Boolean validateFile(File file) {
		Assert.notNull(file);
		Boolean valid = Boolean.FALSE;
		PDBFileReader pr = new PDBFileReader();
		Structure struc = null;
		try {
			struc = pr.getStructure(file);
		} catch (IOException e) {
			valid = Boolean.FALSE;
		}
		String pdbName = struc.getName();
		if (pdbName != null) {
			valid = Boolean.TRUE;
		}
		return valid;
	}
}
